#ifndef REMOTE_CLIENT_CLIENT_H_
#define REMOTE_CLIENT_CLIENT_H_

#include "remote/client/clientcontrolsession.h"
#include "remote/client/task.h"
#include <set>

namespace remote {

struct CreateTunnelSettings {
  typedef boost::shared_ptr<CreateTunnelSettings> Ptr;
  std::string server_addr;
  std::string tunnel_addr;
  std::string token_key;
  uint16 server_port;
  uint16 tunnel_port;
};

class Client : public boost::noncopyable,
  public boost::enable_shared_from_this < Client > {
 public:
  typedef boost::shared_ptr<Client> Ptr;
  Client(boost::asio::io_service &io_service);
  virtual ~Client();

  void GetOnlineSessions();

  bool Start(const char *addr, uint16 port);
  void Stop();
 private:
  void OnConnectFailure(ClientControlSession::Ptr session,
                        uint32 error_code);
  void OnConnectSucceed(ClientControlSession::Ptr session);
  void OnSessionMessage(ClientControlSession::Ptr session,
                        QueryStanza::Ptr stanza);
  // For some task
  void OnOnlineSessions(Task::Ptr task,
                        QueryStanza::Ptr stanza,
                        uint32 error_code);

  void ProcessCreateTunnel(QueryStanza::Ptr stanza);
  void OnTunnelConnect(vzconn::VzConnect::Ptr connect,
                       const boost::system::error_code& err,
                       CreateTunnelSettings::Ptr cts,
                       QueryStanza::Ptr stanza);
  void OnServerConnect(vzconn::VzConnect::Ptr server_connect,
                       const boost::system::error_code& err,
                       CreateTunnelSettings::Ptr cts,
                       QueryStanza::Ptr stanza,
                       vzconn::VzConnect::Ptr tunnel_connect);
 private:
  boost::asio::io_service &io_service_;
  ClientControlSession::Ptr control_session_;
  typedef std::set<Task::Ptr> Tasks;
  Tasks tasks_;
};

}

#endif  // REMOTE_CLIENT_CLIENT_H_
